/*
 * Timers.c
 *
 * Created: 16.01.2014 18:06:14
 *  Author: Hf
 */ 
#include "defines.h"
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#include "MS5541.h"
#include "Timers.h"
#include "globals.h"
#include "OLED.h"
#include "Deco.h"
#include "logbook.h"

log_info_t start_new_dive(void);


void init_Timer2(void){
	TIMSK2 = 0b00000000;	//Make sure all TC2 interrupts are disabled
	TCCR2A = 0b00000000;	//Normal Mode, OC2A and OC2B disconnected
	TCCR2B = 0b00000101;	//prescaler = 128 => an interrupt every 1s
//	TCCR2B = 0b00000111;	//prescaler = 1024 => an interrupt every 8s
	ASSR = 0b00100000;		//disable external clock input, clocked from crystal oscillator
	while (ASSR & ((1<<TCN2UB)|(1<<TCR2AUB)|(1<<TCR2BUB))){}	//Wait until TC2 is updated
	TIMSK2 = 0b00000001;	//enable TC2 overflow interrupt
}

ISR(TIMER2_OVF_vect){
	int16_t dT;
	long int temp;
	int16_t i;

	new_data = 1;
	rtc_sec++;
	if (rtc_sec == 60){
		rtc_sec = 0;
		rtc_min++;
		if (no_flight_time_minutes > 0){
			no_flight_time_minutes--;
		}
		if (desat_time_minutes > 0){
			desat_time_minutes--;
		}
		if (rtc_min == 60){
			rtc_min = 0;
			rtc_hour++;
			if (rtc_hour == 24){
				rtc_hour = 0;
				rtc_day++;
			}
		}
		switch(rtc_month){
			case 1:
			case 3:
			case 5:
			case 7:
			case 8:
			case 10:
			case 12:
				if (rtc_day > 31){
					rtc_day = 1;
					rtc_month++;
				}
				break;
			case 4:
			case 6:
			case 9:
			case 11:
				if (rtc_day > 30){
					rtc_day = 1;
					rtc_month++;
				}
				break;
			case 2:
				if (rtc_day > 28){
					rtc_day = 1;
					rtc_month++;
				}
				break;
		}
		if (rtc_month > 12){
			rtc_month = 1;
			rtc_year++;
		}
	}

	dT = get_temp_diff(&calib_words);
	temperature = get_temperature(dT, &calib_words);
	pressure_mbar = get_pressure(dT, &calib_words);

	if (state == DIVE){
		update_tissues((float)pressure_mbar/1000.0, percentage_N2, delta_time);
	} else {
		if (desat_time_minutes > 0){
			update_tissues((float)pressure_mbar/1000.0, 0.78, delta_time);
		}
	}

	switch (state){
		case IDLE:
			if (surfaced_time < 86401UL){
				surfaced_time++;
			}
			if ((pressure_mbar - p_surface_mbar) > SWITCH_TO_DIVE){
				state = DIVE;
				new_state = 1;
				if (surfaced_time > MAX_INTERVAL){
					//start new dive
					dive_time = 0;
					max_depth = 0;
					min_temperature = temperature;
					log_info = start_new_dive();
				}
			} else {
				temp = p_surface_mbar;
				temp = 31*temp;
				temp = temp + pressure_mbar;
				temp = temp >> 5;
				p_surface_mbar = temp; 
			}
			break;
		case DIVE:
			//make another 7 measurements and average 
			for (i =0; i<7; i++){
				pressure_mbar += get_pressure(dT, &calib_words);
			}
			pressure_mbar = pressure_mbar >> 3;

			dive_time++;
			if ((pressure_mbar - p_surface_mbar) < SWITCH_TO_SURFACED){
				state = SURFACED;
				new_state = 1;
				duration_of_dive = dive_time;
				log_info.duration = dive_time/60;
				log_info.max_depth_m = (uint8_t)(floor(max_depth));
				log_info.max_depth_dm = (uint8_t)(10*(max_depth - log_info.max_depth_m));
				log_info.min_temp = (int8_t)(min_temperature/10);
				write_log_info(log_info);
				surfaced_time = 0;
				shutdown_timer = 0;
				desat_time_minutes = compute_desat_time(p_surface_mbar);
				if (no_flight_time_minutes == 0){
					no_flight_time_minutes = 60*12;
				} else {
					no_flight_time_minutes = 60*24;
				}
			}
			break;
		case SURFACED:
			shutdown_timer++;
			dive_time++;
			if ((pressure_mbar - p_surface_mbar)>SWITCH_TO_DIVE){
				state = DIVE;
				new_state = 1;
			}
			surfaced_time++;
			if (surfaced_time > SURFACE_TIMER_LIMIT){
				state = MENU;
				new_state = 1;
				menu_state = M_AFTERDIVE;
			}
			break;
		case MENU:
			shutdown_timer++;
			surfaced_time++;
			if ((pressure_mbar - p_surface_mbar) > SWITCH_TO_DIVE){
				state = DIVE;
				new_state = 1;
				if (surfaced_time > MAX_INTERVAL){
					//start new dive
					dive_time = 0;
					max_depth = 0;
					min_temperature = temperature;
					log_info = start_new_dive();
				}
			} else {
				temp = p_surface_mbar;
				temp = 31*temp;
				temp = temp + pressure_mbar;
				temp = temp >> 5;
				p_surface_mbar = temp;
			}
			if (shutdown_timer > SHUTDOWN_TIME){
				state = IDLE;
				new_state = 1;
			}
			break;
	}
}


log_info_t start_new_dive(void){
	log_info_t log_info;
	
	log_info.nr = get_nr_of_dives() + 1;
	write_nr_of_dives(log_info.nr);
	log_info.day = rtc_day;
	log_info.month = rtc_month;
	log_info.year = rtc_year;
	log_info.hour = rtc_hour;
	log_info.min = rtc_min;
	log_info.max_depth_m = 0;
	log_info.max_depth_dm = 0;
	log_info.min_temp = temperature;
	log_info.duration = 0;
	
	return log_info;
}